/***************************************************************************/
/* PERSEUS Library version 1.0.6                                           */
/* Stable for 32-bit versions only                                         */
/* Library tested with gcc 4.5.1 on Ubuntu 11.04 and OpenSuse 11.4 64 bits */
/*                                                                         */
/***************************************************************************/
#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <time.h>
#include "perseus.h"
#include "randgen.h"
#include "config.h"
#ifdef DEBUG
#include <stdio.h>
#endif

/***************************************************************************/
/* Random number generator                                                 */
/*                                                                         */
/***************************************************************************/
static RAND_GEN *alea_gen = NULL;

double alea(void)
{
  double dval;

  if (alea_gen == NULL)
    alea_gen = Rand_new();

  Rand_double(alea_gen, &dval);

  return dval;
}


/***************************************************************************/
/* Computation of a long int parity                                        */
/*    if w is a long int then the parity parity(w) is computed as          */
/*       XOR(w[i], i = 0,...31 )                                           */
/*                                                                         */
/***************************************************************************/
unsigned char motpar(unsigned long int w)
 {
  w ^=(w>>32);
  w ^=(w>>16);
  w ^=(w>> 8);
  w ^=(w>> 4);
  w ^=(w>> 2);
  w ^=(w>> 1);

  return(w & 1L);
 }

/***************************************************/
/* Encoder random generation procedure             */ 
/*   Return a NULL pointer upon failure            */
/*   Return a pointer to an encoder otherwise      */
/***************************************************/
PUNCT_CONC_CODE * generateCode()
 {
  PUNCT_CONC_CODE * code = NULL;
  unsigned long int mask;
  unsigned int maxPoly, index, nbzero;
  unsigned int i, j, k;

  /* Encoder variable allocation */
  code = (PUNCT_CONC_CODE *)calloc(1, sizeof(PUNCT_CONC_CODE));
  if (code == NULL)
   {
    perror("calloc");
    return(code);
   }

  /* Random generation of the number of output bits */
  /* [NMIN_GEN, NMIN_GEN + NMAX_GEN]                */
  code->mN = NMIN_GEN + (unsigned int)(NMAX_GEN * alea());

  /* Random generation of the number of input bits  */
  /* [KMIN_GEN, KMIN_GEN + KMAX_GEN] and n - k > 3  */
  while((code->mK=KMIN_GEN + (unsigned int)(KMAX_GEN *alea())) >= (code->mN - 3));

  /* Random generation of the encoder memory        */
  /* [MIN_CONT, MIN_CONT + MAX_CONT]                */
  code->mM= MIN_CONT + (unsigned int)(MAX_CONT * alea());

  /* Random generation of the puncturing matrix width  */
  /* [code->mN, code->mN + 5] */
  code->mMatWidth = code->mN + (unsigned int)(5.0 * alea() );

  /* Random generation of the puncturing matrix weight */
  /* (code->mN*code->mMatWidth - nbzero)               */
  /* where nbzero  = (code->mN*code->mMatWidth/8)      */
  nbzero = ((code->mN*code->mMatWidth) >> 3);
  code->mMatDepth = (code->mN*code->mMatWidth) - nbzero;

  /* Puncturing matrix variable allocation             */
  code->mMatrix = (unsigned char *)calloc(code->mN*code->mMatWidth, sizeof(unsigned char));
  if(code->mMatrix == NULL)
   {
    free(code);
    return(0);
   }

  /* Puncturing matrix generation                      */
  for(i = 0;i < code->mN*code->mMatWidth;i++) code->mMatrix[i] = 1;

  /* Generate the nbzero null entries of the matrix    */
  while(nbzero)
   {
    index = (unsigned int)((code->mMatWidth*code->mN)*alea());
    if(index <= code->mN) continue;
    if(code->mMatrix[index])
     {
      code->mMatrix[index] = 0;
      nbzero--;
     }
   }

  /* Random generation of encoder poynomials */
  code->mPoly=(unsigned long **)calloc(code->mK, sizeof(unsigned long *));
  if(!code->mPoly)
   {
    perror("calloc");
    free(code->mMatrix);
    free(code);
    return(0);
   }

  mask = (0xFFFFFFFFL >> (32 - code->mM));
  /*maxPoly = (unsigned int)(1 << (code->mM + 1));*/
  maxPoly = 1 << (code->mM + 1);

  for(i = 0;i < code->mK;i++)
   {
    code->mPoly[i] = (unsigned long *)calloc(code->mN, sizeof(unsigned long));
    if(code->mPoly[i] == NULL)
     {
      perror("calloc");
      for(k = 0;k < i;k++) free(code->mPoly[k]);
      free(code->mPoly);
      free(code->mMatrix);
      free(code);
      return(0);
     }
   for(j = 0;j < code->mN;j++) code->mPoly[i][j] = (((unsigned long)(alea()*0xFFFFFFFFL) & mask) << 1) | (1L << (code->mM)) | 1;
   }
  return code;
 }
/***************************************************/
/* End of encoder random generation procedure      */
/***************************************************/

#ifdef DEBUG
void Punct_Conc_Code_debug(PUNCT_CONC_CODE *code, FILE *f)
{
  unsigned long i, j;

  if (f == NULL)
    f = stderr;

  fprintf(f, "PUNCT_CONC_CODE:\n");
  fprintf(f, "mN       : %d\n", code->mN);
  fprintf(f, "mK       : %d\n", code->mK);
  fprintf(f, "mM       : %d\n", code->mM);

  for(i = 0; i < code->mK; i++) {
    unsigned long *poly = code->mPoly[i];

    fprintf(f, "mPoly[%4ld]\n", i);
    
#define N_POLY_PER_LINE 8

    for(j = 0; j < code->mN; j++) {
      fprintf(f, "%08lx", poly[j]);
      if (j % N_POLY_PER_LINE == N_POLY_PER_LINE - 1)
	fprintf(f, "\n");
      else
	fprintf(f, " ");
    }
    if (j % N_POLY_PER_LINE != 0)
      fprintf(f, "\n");
  }

  fprintf(f, "mMatWidth: %d\n", code->mMatWidth);

  for(i = 0; i < code->mN * code->mMatWidth; i++) {
    if (i % code->mMatWidth == 0)
      fprintf(f, "[%4ld] ", i);

    fprintf(f, "%1d", code->mMatrix[i]);

    if (i % code->mMatWidth == code->mMatWidth - 1)
      fprintf(f, "\n");
    else
      fprintf(f, " ");
  }
  if (i % code->mMatWidth != 0)
    fprintf(f, "\n");

  fprintf(f, "mMatDepth: %d\n", code->mMatDepth);
}
#endif


/***************************************************/
/* Noise generator secret key                      */ 
/*   Return a NULL pointer upon failure            */
/*   Return a pointer to an key otherwise         */
/***************************************************/
INIT_NOISE_GEN *generateKey(void)
{
  INIT_NOISE_GEN *key = (INIT_NOISE_GEN *)calloc(1, sizeof(INIT_NOISE_GEN));
  unsigned char w;
  unsigned int proba;

  if(key == NULL) {
    perror("Noise generator secret key variable allocation on error!");
    return NULL;
   }

  key->INIT1 = (unsigned long int)(alea() * ULONG_MAX);
  key->INIT2 = (unsigned long int)(alea() * ULONG_MAX);
  key->INIT3 = (unsigned long int)(alea() * ULONG_MAX);
  key->INIT4 = (unsigned long int)(alea() * ULONG_MAX);

  /* Noise probability generation ([0.15, 0.35])*/
  proba = 15 + (unsigned int)(20.0 * alea());

  /* Boolean filtering function generation      */ 
  key->Bf = (unsigned char *)calloc(16, sizeof(unsigned char));
  for (w = 0; w < 16; w++)  {
    unsigned char val = (unsigned char)(99.0 * alea());

    if(val < proba) 
      key->Bf[w] = 1;
   }
  return key;
}

#ifdef DEBUG
void Init_Noise_Gen_debug(INIT_NOISE_GEN *key, FILE *f)
{
  unsigned long i;

  if (f == NULL)
    f = stderr;

  fprintf(f, "INIT_NOISE_GEN:\n");
  fprintf(f, "ULONG_MAX: 0x%lx\n", ULONG_MAX);
  fprintf(f, "INIT1    : 0x%lx\n", key->INIT1);
  fprintf(f, "INIT2    : 0x%lx\n", key->INIT2);
  fprintf(f, "INIT3    : 0x%lx\n", key->INIT3);
  fprintf(f, "INIT4    : 0x%lx\n", key->INIT4);

  fprintf(f, "Bf       :");
  for(i = 0; i < 16; i++)
    fprintf(f, " %1d", key->Bf[i]);
  fprintf(f, "\n");
}
#endif

/***************************************************/
/* Noise generator generation procedure            */
/***************************************************/
int Gen_Noise_Generator(NOISE_GEN * aNGen, INIT_NOISE_GEN * aKey)
{
  /* Feedback polynomial length initialization  */
  aNGen->L1 = LR1;
  aNGen->L2 = LR2;
  aNGen->L3 = LR3;
  aNGen->L4 = LR4;

#if 0
  /* key initialization moved to another function */
  /* Noise generator key generation (102 bits)  */
  aKey->INIT1 = (unsigned long int)(alea() * 0xFFFFFFFFL) & MASK1;
  aKey->INIT2 = (unsigned long int)(alea() * 0xFFFFFFFFL) & MASK2;
  aKey->INIT3 = (unsigned long int)(alea() * 0xFFFFFFFFL) & MASK3;
  aKey->INIT4 = (unsigned long int)(alea() * 0xFFFFFFFFL) & MASK4;
#endif

  return(1);
}
/***************************************************/
/* End of noise generator generation procedure     */
/***************************************************/

/*****************************************************************************************************/
/*****************************************************************************************************/
/*       String transformation functions                                                             */
/*****************************************************************************************************/
/*****************************************************************************************************/

/********************************************************/
/* Transforms a k-bit integer stream into a string of   */
/* chars                                                */
/*  e.g. for k = 5 the sequence of 5-bit integers       */
/* 10 23 25 19 28 17 3 30 20 11 0 0 0 0 0               */
/* gives the following string of chars (in hexa):       */
/*  EA E6 C9 E3 F0                                      */
/********************************************************/
unsigned char * int_to_char(unsigned long * aTab, unsigned long aLength, unsigned int k, unsigned int N, unsigned long *size)
 {
  unsigned long i, reg = 0LL, j, regsize;
  unsigned char flag = 0;
  unsigned char * data = NULL;

  aLength = aLength - N;
  *size = ((aLength*k) >> 3 ) + 1;

  data = (unsigned char *)calloc(((*size) + 2), sizeof(unsigned char));
  if(data == NULL) return NULL;

  regsize = 0L;
  flag = 0;
  j = 0LL;
  i = 0LL;
  while(1)
   {
    while(regsize < 48)
     {
      reg |= (aTab[i++] << regsize);
      regsize +=k;
      if(i == aLength)
       {
        flag = 1;
        break;
       }
      while(regsize > 8)
       {
        data[j++] = reg & 0xFF;
        reg >>= 8;
        regsize -= 8;
       }
      if(flag)
       {
        data[j++] = reg & 0xFF;
        data[j] = '\0';
        *size = j;
        return(data);
       }
     }
   }
 }
/********************************************************/
/* End of the int_to_char procedure                     */
/********************************************************/

/********************************************************/
/* Transforms a hexa stream into a binary stream        */
/*  e.g.  AB18 ---> 1010101100011000                    */
/*                                                      */
/* the first integer of aDataHex is the length of the   */
/* last hexa symbol                                     */
/*  e.g 3AB184 ---> 1010101100011000010                 */
/********************************************************/
unsigned char hex_to_Binchar(unsigned char * aDataHex, unsigned long aLength, unsigned char ** aDataBin, unsigned long * aDataBinLength)
 {
  unsigned long i = 0, up_size;
  unsigned char j = 0, tmp, rest;
  unsigned char cis[23] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15};

  *aDataBinLength = 0L;
  if(aLength <= 1)
   {
    *aDataBin = NULL;
    return(0);
   }

  rest = (unsigned char)aDataHex[0] -'0';
  if (rest > 3)
  {
    *aDataBin = NULL;
    return 0;
  }

  *aDataBin = (unsigned char *)calloc(((aLength - 1) << 2) + rest + 1, sizeof(unsigned char));
  if((*aDataBin) == NULL) return(0);

  if(rest) up_size = aLength - 1;
  else     up_size = aLength;
  for(i = 1; i < up_size;i++)
   {
    tmp = cis[aDataHex[i] - '0'];
    (*aDataBin)[(*aDataBinLength)++] = (tmp >> 3) & 1;
    (*aDataBin)[(*aDataBinLength)++] = (tmp >> 2) & 1;
    (*aDataBin)[(*aDataBinLength)++] = (tmp >> 1) & 1;
    (*aDataBin)[(*aDataBinLength)++] =  tmp & 1;
   }

  /* Let us process the last Hex symbol if any  */
  if(rest)
   {
    tmp = cis[aDataHex[aLength - 1] - '0'];
    for(j = 3;j >= (4 - rest);j--) (*aDataBin)[(*aDataBinLength)++]= (tmp >> j) & 0x1;
   }
  (*aDataBin)[(*aDataBinLength)]='\0';

  return(1);
 }
/********************************************************/
/* End of hex_to_Binchar procedure                      */
/********************************************************/

/********************************************************/
/* Transforms string of char into binary                */
/*  ABC --> 01000001 01000010 01000011                  */
/********************************************************/
unsigned char char_to_bin(unsigned char * aData, unsigned long aLength, unsigned char aK, unsigned char aN, unsigned char ** aDataBin, unsigned long * aNewLength)
 {
  unsigned char j;
  unsigned long i, k = 0L;
  unsigned int l, padding;

#undef EDDY_FIX
#ifdef EDDY_FIX
  padding = (unsigned int) (((aK - (unsigned  char)((aLength >> 3) % aK)) %aK ) + (aK*(aN-1)));
#else
  padding = (unsigned int) (((aK - (unsigned  char)((aLength >> 3) % aK)) % aK) + (aK*aN));
#endif

  *aDataBin = (unsigned char *)calloc(((aLength << 3) + padding), sizeof(unsigned char) );
  if(aDataBin == NULL) return(0);

  for(i = 0;i < aLength;i++)
   {
    for(j = 0;j < 8;j++) (*aDataBin)[k++] = (aData[i] >> j) & 1;
   }
  for(l = 0;l < padding;l++) (*aDataBin)[k++] = 0;
  *aNewLength = k;
  return(1);
 }
/********************************************************/
/* End of char_to_bin procedure                         */
/********************************************************/

/********************************************************/
/* Transforms a binary stream into a hexa stream        */
/*  e.g.  1010101100011000 ---> AB18                    */
/*                                                      */
/* the first integer in aHexData is the length of the   */
/* last hexa symbol                                     */
/*  e.g 1010101100011000010 ---> 3AB184                 */
/********************************************************/
unsigned char ** bin_to_charHex(unsigned char * aBinData, unsigned long aLength, unsigned char ** aHexData, unsigned long * aHexDataLength)
 {
  unsigned long i, k, up_size;
  unsigned char j, tmp;
  unsigned char trans[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
   
  /* Alength/4 + 1 gives the length of final hexa stream */
  /* We add one for the first padding value and one for  */
  /* the string end marker                               */

  if(aLength & 0x3) up_size = (aLength >> 2) + 3;
  else              up_size = (aLength >> 2) + 2;

  *aHexData = (unsigned char *)calloc(up_size, sizeof(unsigned char));
  if(*aHexData == NULL) return(aHexData);

  k = 1;
  for(i = 0L;i < (aLength - (aLength & 0x3));i +=4)
   {
    tmp = (unsigned char) ((aBinData[i] << 3) | (aBinData[i + 1] << 2) | (aBinData[i + 2] << 1) | aBinData[i + 3]);
    (*aHexData)[k] = trans[tmp];
    k++;
   }

  j = 0L;
  tmp = 0;
  for(i = (aLength - (aLength & 0x3)); i < aLength;i++)
   {
    tmp |= (unsigned char)((aBinData[i] << (3 - j)));
    j++;
   }
  (*aHexData)[0] = trans[j];
  if(j)
   {
    (*aHexData)[k++] = trans[tmp];
    (*aHexData)[k] = '\0';
   }
  else (*aHexData)[k] = '\0';
  (*aHexDataLength) = k;
    
  return(aHexData);
 }
/********************************************************/
/* End of the bin_to_charHex procedure                  */
/********************************************************/

/***************************************************/
/* Noise generation and combination procedure      */
/* Input parameters:                               */
/*  - encoded punctured data (Data array)          */
/*  - noise generator (aNGen)                      */
/*  - data size (DataSize)                         */
/*  - noise generator initialization (aKey)        */
/* (parallel) 8-bit version                        */
/***************************************************/
int Gen_Noise(unsigned char * Data, NOISE_GEN * aNGen, unsigned long int DataSize, INIT_NOISE_GEN * aKey)
 {
  unsigned char x, outblock, reb, j;
  unsigned long int i;

  /* Initialisation du codeur avec la clef */
  /* Le & MASK qui était fait dans l'initialisation a été déplacé ici */
  aNGen->Reg1 = aKey->INIT1 & MASK1;
  aNGen->Reg2 = aKey->INIT2 & MASK2;
  aNGen->Reg3 = aKey->INIT3 & MASK3;
  aNGen->Reg4 = aKey->INIT4 & MASK4;

  for(i = 0L;i < DataSize;i++)
   {
    outblock = 0;
    for(j = 0;j < 8;j++)
     {
      x = aKey->Bf[(aNGen->Reg1 & 1) | ((aNGen->Reg2 & 1) << 1) | ((aNGen->Reg3 & 1) << 2) | ((aNGen->Reg4 & 1) << 3)];
      outblock |= (unsigned char)((x << j));

      reb = motpar(aNGen->Reg1 & POLY1);
      aNGen->Reg1  >>= 1;
      aNGen->Reg1 |= (reb << (aNGen->L1 - 1));

      reb = motpar(aNGen->Reg2 & POLY2);
      aNGen->Reg2  >>= 1;
      aNGen->Reg2 |= (reb << (aNGen->L2 - 1));

      reb = motpar(aNGen->Reg3 & POLY3);
      aNGen->Reg3  >>= 1;
      aNGen->Reg3 |= (reb << (aNGen->L3 - 1));

      reb = motpar(aNGen->Reg4 & POLY4);
      aNGen->Reg4  >>= 1;
      aNGen->Reg4 |= (reb << (aNGen->L4 - 1));
     }
    Data[i] ^= outblock;
   }
  return(1);
 }
/****************************************************/
/* End of noise generation/combination procedure    */
/****************************************************/

/*****************************************************************************************************/
/*****************************************************************************************************/
/*                                        PCC functions                                              */
/* Enable to get the different encoder parameters directly while preserving the code readability     */
/*****************************************************************************************************/
/*****************************************************************************************************/

/*  Get the number of encoder outputs   */
unsigned int pcc_getN(PUNCT_CONC_CODE * p)
 {
  return p->mN;
 }

/*  Get the number of encoder inputs    */
unsigned int pcc_getK(PUNCT_CONC_CODE * p)
 {
  return p->mK;
 }

/*  Get the encoder memory size         */
unsigned int pcc_getM(PUNCT_CONC_CODE * p)
 {
  return p->mM;
 }

/* Get the encoder polynomials          */
unsigned long * * pcc_getPoly(PUNCT_CONC_CODE * p)
 {
  return p->mPoly;
 }

/* Get the encoder punturing matrix width */
unsigned int pcc_getMatWidth(PUNCT_CONC_CODE * p)
 {
  return p->mMatWidth;
 }

/* Get the encoder punturing matrix       */
unsigned char * pcc_getMatrix(PUNCT_CONC_CODE * p)
 {
  return p->mMatrix;
 }

/*****************************************************************************************************/
/*****************************************************************************************************/
/*                                 End of PCC functions                                              */
/*****************************************************************************************************/
/*****************************************************************************************************/


/*********************************************************/
/* This procedure computes mN output bits                */
/*                                                       */
/* In parameters:                                        */
/*  - aPoly ---> N polynoms                              */
/*  - aBit  ---> a bit that represents the k-th entry    */
/*  - aMemory ---> the k-th memory                       */
/*                                                       */
/* Out parameters:                                       */
/*  - value ---> an integer describing the N output bits */
/*               coded as vN VN-1 ... v1 v0              */
/*********************************************************/
void compute(unsigned int mN, unsigned int mM, unsigned long * aPoly, unsigned char aBit, unsigned long aMemory, unsigned int *value)
 {
  unsigned int i, j, val;

  for(i = 0;i < mN;i++) 
   {
    val = (aPoly[i] & aBit) & 1;

    for(j = 1;j <= mM; ++j) val ^= (((aPoly[i] >> j) & 1) & (aMemory >> (j-1)));
    *value <<= 1;
    *value  |= val;
   }
 }
/*********************************************************/
/* End of compute procedure                              */
/*********************************************************/

/*********************************************************/
/* This procedure performs the puncturing of the encoded */
/* stream according to the encoder puncturing pattern    */
/*                                                       */
/* In parameters:                                        */
/*  - aStream ---> the array of encoded bits             */
/*  - aLength ---> the number of encoded bits            */
/*                                                       */
/* Out parameters:                                       */
/*  - aNewStream ---> the result of puncturing (binary   */
/*                    stream)                            */
/*  - aNewLength ---> size of aNewStream with            */
/*                    aNewLength <= aLength              */
/*********************************************************/
unsigned char pcc_puncture(PUNCT_CONC_CODE *p,unsigned char * aStream, unsigned long aLength, unsigned char ** aNewStream, unsigned long *aNewLength)
 {
  unsigned long i;
  unsigned char j = 0;

  *aNewLength = 0LL;
  *aNewStream = (unsigned char *)calloc(aLength, sizeof(unsigned char));
  if(*aNewStream == NULL) return(0);

  /* The last n bits are left unpunctured */
  for(i = 0;i < aLength - 1;i++) 
   {
    j %= (unsigned char)((p->mMatWidth)*(p->mN));
    if((p->mMatrix)[j]) 
     {
      (*aNewStream)[*aNewLength] = aStream[i];
      (*aNewLength)++;
     }
    j++;
   }
   
  (*aNewStream)[*aNewLength] = aStream[aLength - 1];
  (*aNewLength)++;
  return(1);
 }
/*********************************************************/
/*  End of pcc_puncture procedure                        */
/*********************************************************/

/*********************************************************/
/* This procedure removes the puncturing of the encoded  */
/* stream according to the encoder puncturing pattern    */
/*                                                       */
/* In parameters:                                        */
/*  - aStream ---> the array of punctured bits           */
/*  - aLength ---> the number of punctured bits          */
/*                                                       */
/* Out parameters:                                       */
/*  - aNewStream ---> an array of unpunctured bits       */
/*                    (punctured symbol are marked with  */
/*                     the 0xF value)                    */
/*  - aNewLength ---> size of aNewStream with            */
/*                    aNewLength <= aLength              */
/*********************************************************/
unsigned char pcc_unpuncture(PUNCT_CONC_CODE * p,unsigned char * aStream, unsigned long aLength, unsigned char ** aNewStream, unsigned long *aNewLength)
 {
  unsigned long i, taille;
  unsigned char j;
    
  taille = (aLength + (aLength/((p->mN*p->mMatWidth) - p->mMatDepth)+1)*p->mMatDepth); 
  *aNewLength = 0LL;
  *aNewStream = (unsigned char *)calloc(taille, sizeof(unsigned char));
  if((*aNewStream) == NULL) return(0);

  i = 0LL;
  j = 0;
  while(i < (aLength-1)) 
   {
    j %= (unsigned char) ((p->mMatWidth)*(p->mN));

    if(!((p->mMatrix)[j])) (*aNewStream)[(*aNewLength)++] = 0xF;
    else (*aNewStream)[(*aNewLength)++] = aStream[i++];
    j++;
   }
  /* Last bit is not punctured*/
  (*aNewStream)[(*aNewLength)++] = aStream[i];
  return(1);
 }
/*********************************************************/
/*  End of pcc_unpuncture procedure                      */
/*********************************************************/

/*****************************************************************************************************/
/*****************************************************************************************************/
/*                                    Position function                                              */
/*****************************************************************************************************/
/*****************************************************************************************************/

position * position_new(unsigned int input, position * previous)
 {
  position * p = (position *)malloc(sizeof(position));
  if(p == NULL) return(NULL);
    
  p->input = input;
  p->previous = previous;
  p->memory = NULL;
  return(p);
 }

unsigned char position_copyMemory(position * p,unsigned long *aMemory, unsigned char aLength)
 {
  unsigned char i;

  p->memory = (unsigned long *)calloc(aLength, sizeof(unsigned long));
  if(p->memory == NULL) return(0);

  for(i = 0;i < aLength;i++) p->memory[i]=aMemory[i];
  return(1);
 }

void position_delete(position *p)
 {
  if(p != NULL)
   {
    free(p->memory);
    p->previous=0;
   }
 }

void position_setPrevious(position * p, position * aPrevious)
 {
  p->previous = aPrevious;
 }

unsigned long * position_getMemory(position *p)
 {
  return p->memory;
 }

position * position_getPrevious(position *p)
 {
  return p->previous;
 }

unsigned int position_getInput(position *p)
 {
  return p->input;
 }

/*****************************************************************************************************/
/*****************************************************************************************************/
/*                                       Noded function                                              */
/*****************************************************************************************************/
/*****************************************************************************************************/

/*************************************************************************/
/* Initializes a node in the Viterbi lattice                             */
/*************************************************************************/
noded * noded_init(char metric, unsigned long positionNumber, position ** block)
 {
  noded * n = (noded *)calloc(1, sizeof(noded));  
  if(n == NULL) return(NULL);

  n->metric = metric;
  n->positionNumber = positionNumber;
  n->Block = block;

  return(n);
 }


unsigned char noded_addPosition(noded *n,char aMetric,unsigned int aInput,unsigned long *aMemory, unsigned char aMemoryLength, position *aPrevious)
 {
  unsigned char ret;
  position * p; 

  n->Block= (position **)realloc(n->Block, sizeof(position*)*(n->positionNumber + 1));
  if(n->Block == NULL) return(0);

  p = position_new(aInput, aPrevious);
  if(p == NULL) return(0);

  ret = position_copyMemory(p,aMemory, aMemoryLength); 
  if(ret == 0) return(0);

  n->positionNumber++;
  n->Block[n->positionNumber-1] = p;
  n->metric = aMetric;

  return(1);
 }

unsigned char noded_replaceBlock(noded *n,char aMetric,unsigned int aInput,unsigned long *aMemory, unsigned char aMemoryLength, position *aPrevious)
 {
  unsigned char ret = 0;
  unsigned long i;
  position * p;

  for(i = 0;i < n->positionNumber;i++)
   {
    position_delete(n->Block[i]);
    free(n->Block[i]);
   }
  free(n->Block);
  n->positionNumber = 1;
  n->Block = (position **)malloc(sizeof(position*));
  if(n->Block == NULL) return(0);

  p = position_new(aInput, aPrevious);
  if(p == NULL) return(0);

  ret = position_copyMemory(p,aMemory, aMemoryLength); 
  if(ret == 0) return(0);
  n->Block[n->positionNumber - 1] = p;
  n->metric = aMetric;

  return(1);
 }
 
/* Tests whether a node is empty or not */
char noded_isEmpty(noded* n)
 {
  return((n->positionNumber)?1:0);
 }

/* Deletes a lattice node               */
void noded_delete(noded * n)
 {
  unsigned long i;
  if(n != NULL)
   {
    for(i = 0;i < n->positionNumber;i++)
     { 
      position_delete(n->Block[i]);
      free(n->Block[i]);
     }
    free(n->Block);
   }
 }

/* Set a metric value to a node         */
void noded_setMetric(noded * n, char aMetric)
 {
  n->metric = aMetric;
 }

/* Get the metric value of a node       */
char noded_getMetric(noded *n)
 {
  return n->metric;
 }

/* Get the location number of a node in the lattice */
unsigned long noded_getPositionNumber(noded *n)
 {
  return n->positionNumber;
 }

/* Get the memory content of a lattice node at a given location */
unsigned long * noded_getMemory(noded *n,unsigned long aPosition)
 {
  return position_getMemory(n->Block[aPosition]);
 }

/* get the location address of a node in a lattice              */
position * noded_getAddressPosition(noded *n,unsigned long aPosition)
 {
  return n->Block[aPosition]; 
 }

/*****************************************************************************************************/
/*****************************************************************************************************/
/*****************************************************************************************************/
/*                       Viterbi lattice functions                                                   */
/*****************************************************************************************************/
/*****************************************************************************************************/
/*****************************************************************************************************/

/*****************************************************************************************************/
/*  Viterbi lattice initialization procedure                                                         */
/*  In parameters:                                                                                   */
/*     - the encoder                  ---> aPcc                                                      */
/*     - the data to decode           ---> aData                                                     */
/*     - the length of data to decode ---> aLength                                                   */
/*                                                                                                   */
/*  The function returns a pointer to the Viterbi lattice initialized with the data to decode and    */
/*  the encoder parameters                                                                           */  
/*****************************************************************************************************/
viterbi * viterbi_init(PUNCT_CONC_CODE * aPcc,unsigned char * aData, unsigned long aLength)
 {
  unsigned long i;
  unsigned int j;
    
  viterbi * v = (viterbi *)calloc(1, sizeof(viterbi));

  if(v == NULL) return(v);

  v->aCode = aPcc;                                                  /* Encoder parameters               */
  v->data = aData;                                                  /* Data to decode                   */
  v->dataLength = aLength;                                          /* Length of data to decode         */
  v->height = (unsigned int)(1 << (pcc_getN(v->aCode)));                          /* Height of the Viterbi lattice    */
  v->width = (unsigned long)(floor(v->dataLength/(pcc_getN(v->aCode))));          /* Width of the Viterbi lattice     */
  v->treillis = (noded ***)calloc((v->width + 1), sizeof(noded**)); /* Lattice initialization (level 1) */

  if(v->treillis == NULL)
   {
    free(v);
    return(v);
   }
    
  for(i = 0;i < (v->width + 1);i++)                                 /* Lattice initialization (level 2) */
   {
    v->treillis[i] = (noded **)calloc(v->height, sizeof(noded*));
    if(v->treillis[i] == NULL)
     {
      for(j = i - 1;j > 0;j--) free(v->treillis[j]);
      free(v->treillis[0]);
      free(v->treillis);
      free(v);
      return(v);
     }
    for(j = 0;j < v->height;j++) v->treillis[i][j] = NULL;          /* Lattice initialization (level 3) */
   }
  return(v);
}
/*****************************************************************************************************/
/*  End of the Viterbi lattice initialization procedure                                              */
/*****************************************************************************************************/

/*****************************************************************************************************/
/*  Viterbi lattice variable made free                                                               */
/*  In parameters:                                                                                   */
/*     - a Viterbi lattice structure                                                                 */
/*****************************************************************************************************/
void viterbi_delete(viterbi * v)
 {
  unsigned long i;
  unsigned int j;

  for(i = 0;i < v->width + 1;i++)
   {
    for(j = 0;j < v->height;j++)
     {
      if((v->treillis[i][j]) != NULL) noded_delete(v->treillis[i][j]);
      free(v->treillis[i][j]);
     }
    free(v->treillis[i]);
   }
  free(v->treillis);
 }
/*****************************************************************************************************/
/*  End of Viterbi lattice variable removing procedure                                               */
/*****************************************************************************************************/

void viterbi_setMetric(viterbi *v,unsigned long x,unsigned int y, char aMetric)
 {
  noded_setMetric(v->treillis[x][y],aMetric);
 }

char viterbi_getMetric(viterbi *v, unsigned long x, unsigned int y)
 {
  return(noded_getMetric(v->treillis[x][y]));
 }

char viterbi_isEmpty(viterbi *v, unsigned long x, unsigned int y)
 {
  return((v->treillis[x][y] == NULL));
 }

unsigned int viterbi_NumberOfPosition(viterbi *v, unsigned long x, unsigned int y)
 {
  return(noded_getPositionNumber(v->treillis[x][y]));
 }

unsigned long * viterbi_getMemory(viterbi *v, unsigned long x, unsigned int y, unsigned int aPosition)
 {
  return(noded_getMemory(v->treillis[x][y], aPosition));
 }

position * viterbi_getAddressPosition(viterbi *v,unsigned long x, unsigned int y, unsigned int aPosition)
 {
  return(noded_getAddressPosition(v->treillis[x][y], aPosition));
 }

unsigned char distance(unsigned char * a, unsigned int b, unsigned char length, unsigned long begin)
 {
  unsigned char i, dist = 0;
  for(i = 0;i < length;i++) 
   {
    /* Tests whether this position corresponds to a punctured bit or not */
    if(a[begin] != 0xF) dist += ((unsigned char)(a[begin] & 0x1) ^ (unsigned char)(b >> (length - 1 - i) & 0x1)); 
    begin++;
   }
  return(dist);
 }

unsigned char viterbi_addPosition(viterbi *v, unsigned long x, unsigned int y, char aMetric, unsigned int aInput, 
                                  unsigned long *aMemory, unsigned char aMemoryLength, position *aPrevious)
 {
  unsigned char ret = 0;

  if(v->treillis[x][y] == NULL)
   {
    v->treillis[x][y] = noded_init(0, 0L, 0);
    if(v->treillis[x][y] == NULL) return(0);

    ret = noded_addPosition(v->treillis[x][y], aMetric, aInput, aMemory, aMemoryLength, aPrevious);
    if(ret == 0) return(0);
    }
    else
     {
      if(viterbi_getMetric(v,x,y)>aMetric)
       {
        ret = noded_replaceBlock(v->treillis[x][y],aMetric,aInput,aMemory,aMemoryLength, aPrevious);
        if(ret == 0) return(0);
       }
      else
       {
        if((viterbi_getMetric(v,x,y) == aMetric) || (viterbi_NumberOfPosition(v,x,y) == 0)) 
         {
          ret = noded_addPosition(v->treillis[x][y],aMetric,aInput,aMemory,aMemoryLength, aPrevious);
          if(ret == 0) return(0);
         }
       }
    }
  return(1);
}

/*****************************************************************************************************/
/*  Follows the Viterbi lattice backwards to find the optimal path                                   */
/*  In parameters:                                                                                   */
/*     - the Viterbi lattice ---> v                                                                  */
/*                                                                                                   */
/*  Out parameters:                                                                                  */
/*     - the decoded data           ---> aDataDecoded                                                */
/*     - the length of decoded data ---> dataLength                                                  */
/*****************************************************************************************************/
unsigned char viterbi_backward(viterbi *v, unsigned char ** aDataDecoded, unsigned long *dataLength)
 {
  signed char minMetric = -1, metric = 0;
  position * tmp;
  unsigned long i;
  unsigned long *table = NULL;
  unsigned int j, min = 0xFFFF; 

  for(j = 0;j < v->height;++j)
   {
    if(!viterbi_isEmpty(v,v->width,j))
     {
      metric = viterbi_getMetric(v,v->width,j);
      if((metric < minMetric) || (minMetric == -1)) 
       {
        min = j;
        minMetric = metric; 
       }
     }
   }

  if((min == 0xFFFF) || viterbi_isEmpty(v,v->width,min)) return(0);

  tmp = viterbi_getAddressPosition(v,v->width,min,0);
  i = v->width;
  table = (unsigned long *)calloc(v->width, sizeof(unsigned long));
  if(table == NULL) return(0);

  while((tmp) && (i > 0)) 
   {
    i--;
    table[i] = position_getInput(tmp);
    tmp=position_getPrevious(tmp);
   }

  *aDataDecoded = int_to_char(table, v->width, pcc_getK(v->aCode), pcc_getN(v->aCode), dataLength);
  if(*aDataDecoded == NULL)
   {
    free(table);
    return(0);
   }
  free(table);
  return(1);
 }
/*****************************************************************************************************/
/* End of the viterbi_backward procedure                                                             */ 
/*****************************************************************************************************/

/*****************************************************************************************************/
/*  Viterbi lattice core decoding procedure                                                          */
/*  In parameters:                                                                                   */
/*     - the Viterbi lattice built from the encoder and the encoded data ---> v                      */
/*                                                                                                   */
/*  Out parameters:                                                                                  */
/*     - the decoded data           ---> aData                                                       */
/*     - the length of decoded data ---> aLength                                                     */
/*                                                                                                   */
/*****************************************************************************************************/
unsigned char viterbi_decode(viterbi * v, unsigned char ** aDataDecoded, unsigned long *aDataDecodedLength)
 {
  /* Get the encoder data          */
  unsigned int mN = pcc_getN(v->aCode);
  unsigned int mK = pcc_getK(v->aCode);
  unsigned int mM = pcc_getM(v->aCode);
  unsigned long ** mPoly = pcc_getPoly(v->aCode);

  /* Internal working variables    */
  unsigned long i;
  unsigned long * nextmemory, * memory, bitmask, positionNumber, m;
  unsigned char ret, MaxMetric = 0, abit, k, tmpdist;
  unsigned int input, value = 0, valueFin, j, n_bit;

  nextmemory = (unsigned long *)calloc(mK, sizeof(unsigned long));
  if(nextmemory == NULL) return(0);
    
  ret = viterbi_addPosition(v, 0, 0, 0, 0, nextmemory, mK, 0);
  if(ret == 0)
    {
     free(nextmemory);
     return(0);
    }

  bitmask = (0xFFFFFFFFL >> (32 - mM));

  for(i = 0;i < v->width;i++) 
   {
    for(j = 0;j < v->height;++j) 
     {
      if (viterbi_isEmpty(v, i, j)) continue;
      positionNumber = viterbi_NumberOfPosition(v,i,j);

      for(m = 0;m < positionNumber;m++) 
       {
        memory = viterbi_getMemory(v, i, j, m);

        for(input = 0;input <((unsigned int)(1) << mK);++input)
         {
          valueFin = 0;
          for(k = 0;k < mK;++k) 
           {
            abit = (input >> k) & 0x1;
            compute(mN, mM, mPoly[k], abit, memory[k], &value);
            valueFin ^= value;
            nextmemory[k] = ((memory[k] << 1)| abit) & bitmask;
            value = 0;
           }
          n_bit = i*mN;              /* Integer overflow ---> n_bit devrait etre du type long ? */
          tmpdist = distance(v->data, valueFin, mN, n_bit);
          tmpdist += viterbi_getMetric(v, i, j);
          if(tmpdist <= MaxMetric)
           {
            ret = viterbi_addPosition(v, i + 1, valueFin, tmpdist, input, nextmemory, mK, viterbi_getAddressPosition(v, i, j, m));
            if(ret == 0)
             {
              free(nextmemory);
              return(0);
             }
           }
         }
       }
     }
   }

  /* Look for the best path in the Viterbi lattice          */
  /* Maximum-likelyhood decoding                            */
  ret = viterbi_backward(v, aDataDecoded, aDataDecodedLength);
  if(ret == 0)
   {
    free(nextmemory);
    return(0);
   }
  free(nextmemory);
  return(1);
 }
/*****************************************************************************************************/
/*  End of the Viterbi lattice core decoding procedure                                               */
/*****************************************************************************************************/

/*****************************************************************************************************/
/*****************************************************************************************************/
/*                                   End Pcc functions                                               */
/*****************************************************************************************************/
/*****************************************************************************************************/

/*****************************************************************************************************/
/*****************************************************************************************************/
/*  Encoding procedure                                                                               */
/*  In parameters:                                                                                   */
/*     - the encoder        ---> aCode                                                               */
/*     - the data to encode ---> (data array)                                                        */
/*     - the length of data ---> length                                                              */
/*                                                                                                   */
/*  Out paramaters:                                                                                  */
/*     - the encoded data array   ---> dataCoded array                                               */
/*     - the encoded data length  ---> codedLength                                                   */
/*****************************************************************************************************/
/*****************************************************************************************************/

unsigned int pcc_code(PUNCT_CONC_CODE * aCode, unsigned char * data, unsigned long length, 
                       unsigned char ** dataCoded, unsigned long * codedLength, NOISE_GEN * aNGen, INIT_NOISE_GEN * aKey)
 {
  /***************/
  unsigned int mN = pcc_getN(aCode);
  unsigned int mK = pcc_getK(aCode);
  unsigned int mM = pcc_getM(aCode);
  unsigned long **mPoly = pcc_getPoly(aCode);
  /***************/
  unsigned char abit, ret;
  unsigned long i, j;
  unsigned int k, value, tmpvalue;
  unsigned long * memory, bitmask;
  unsigned long binsize, nsize;
  unsigned char * databin, * valueFin, * nstream;

  memory= (unsigned long *)calloc(mK, sizeof(unsigned long));

  if(memory == NULL) return(0);

  bitmask = (0xFFFFFFFF >> (32 - mM));

  ret = char_to_bin(data, length, mK, mN, &databin, &binsize);
  if(ret == 0)
   {
    free(memory);
    return(0);
   }
    
   valueFin = (unsigned char *)calloc(((binsize*mN)) + 1, sizeof(unsigned char)); /* Modif here  binsize*mN/mK ---> binsize*mN */
   if(valueFin == NULL)
    {
     free(databin);
     free(memory);
     return(0);
    }
        
    i = 0;
    j = 0;
    value = 0;
    while(i < binsize) 
     {
      for(k = 0;k < mK;k++) 
       {
        tmpvalue = 0;
        if(i >= binsize) break;
        abit = databin[i++] & 0x1; 
        compute(mN, mM, mPoly[k], abit, memory[k], &tmpvalue);
        memory[k] = (memory[k] << 1 | abit) & bitmask;
        value ^= tmpvalue;
       }
      for(k = 0;k < mN;k++) valueFin[j++] = value >> (mN - k - 1) & 0x1;
      value=0;
     }
    j--;
    /* Data are now punctured (binary ---> binary)           */
    ret = pcc_puncture(aCode, valueFin, j, &nstream, &nsize);
    if(ret == 0)
     {
      free(valueFin);
      free(databin);
      free(memory);
      return(0);
     }
    
    /* Punctured data are transcoded (binary ---> hex)        */
    dataCoded = bin_to_charHex(nstream, nsize, dataCoded, codedLength);
    if(*dataCoded == NULL)
     {
      free(nstream);
      free(valueFin);
      free(databin);
      free(memory);
      return(0);
     }
    
    /* Noise is combined to the encoded data                  */
    ret = Gen_Noise(*dataCoded, aNGen, *codedLength, aKey);
    if(ret != 1)
     {
      free(nstream);
      free(valueFin);
      free(databin);
      free(memory);
      return(0);
     }
/*ajout non ?*/
      free(nstream);
      free(valueFin);
      free(databin);
      free(memory);
/* Fin ajout non ?*/
  return(1);
 }
/*****************************************************************************************************/
/*****************************************************************************************************/
/*  End of encoding procedure                                                                        */
/*****************************************************************************************************/
/*****************************************************************************************************/

/*****************************************************************************************************/
/*****************************************************************************************************/
/*  Decoding procedure                                                                               */
/*  In parameters:                                                                                   */
/*     - the encoder         ---> aCode                                                              */
/*     - the data to decode  ---> dataCoded                                                          */
/*     - encoded data length ---> length                                                             */
/*  Out parameters:                                                                                  */
/*     - the decoded data array   ---> dataDecoded                                                   */
/*     - the decoded data length  ---> dataLength                                                    */
/*****************************************************************************************************/
/*****************************************************************************************************/
unsigned char pcc_decode(PUNCT_CONC_CODE * aCode, NOISE_GEN * aNGen, INIT_NOISE_GEN * aKey, 
                         unsigned char * dataCoded, unsigned long length, unsigned char ** dataDecoded, unsigned long * dataLength)
 {
  unsigned char ret;
  unsigned char * databin = NULL, * dataUnpuctured = NULL;
  unsigned long binsize = 0LL, unpucturedSize = 0LL;
  viterbi * v = NULL;

  /* Noise is removed from to the encoded data              */
  ret = Gen_Noise(dataCoded, aNGen, length, aKey);
  if(ret != 1) return(0);

  /* Hex data are transcoded (Hex ---> binary      )        */
  ret = hex_to_Binchar(dataCoded, length, &databin, &binsize);
  if(ret == 0)
   {
    free(databin);
    return(0);
   }

  /* Unpuncture binary data                                 */
  ret = pcc_unpuncture(aCode, databin, binsize, &dataUnpuctured, &unpucturedSize);
  if(ret == 0)
   {
    free(databin);
    return(0);
   }

  /* Initialization of the Viterbi lattice for decoding     */
  v = viterbi_init(aCode, dataUnpuctured, unpucturedSize);

  if(v == NULL)
   {
    free(dataUnpuctured);
    free(databin);
    return(0);
   }

  /* Performs the Viterbi decoding step itself              */
  ret = viterbi_decode(v, dataDecoded, dataLength);
  if(ret == 0)
   {
    viterbi_delete(v);
    free(v);
    free(dataUnpuctured);
    free(databin);
    return(0);
   }
/* ajout non ? */
    viterbi_delete(v);
    free(v);
    free(dataUnpuctured);
    free(databin);
/* fin ajout non ? */
  return(1);
 }
/*****************************************************************************************************/
/*****************************************************************************************************/
/*  End of decoding procedure                                                                        */
/*****************************************************************************************************/
/*****************************************************************************************************/


/***************************************************/
/* This procedure removes the code and free the    */
/* relevant fields/data structure.                 */
/* A new code can be generated                     */
/***************************************************/
void delete_code(PUNCT_CONC_CODE * code)
 {
  unsigned char i;

  if (code == NULL)
     return;

  for(i = 0;i < code->mK;i++) free(code->mPoly[i]);
  free(code->mPoly);
  free(code->mMatrix);
  free(code);
 }

int perseus_init(libperseus_hl_t *lhl)
{
   unsigned int k;

   lhl->Pcc = generateCode();                                                                                                                                                                                                           
   if (lhl->Pcc == NULL)
      {
         return -1;
      }

   lhl->aKey = generateKey();

   if (lhl->aKey == NULL)
      {
	return -1;
      }

   lhl->NGen = (NOISE_GEN *)calloc(1, sizeof(NOISE_GEN));
   if (lhl->NGen == NULL)
      {
         for(k = 0;k < lhl->Pcc->mK;k++) free(lhl->Pcc->mPoly[k]);
         free(lhl->Pcc->mPoly);
         free(lhl->Pcc->mMatrix);                                                                                                                                                                                               
         free(lhl->Pcc);
         free(lhl->aKey);

         return -1;
      }

   if(!Gen_Noise_Generator(lhl->NGen, lhl->aKey)) 
      {
         /*for(k = 0;k < lhl->Pcc->mK;k++) free(lhl->Pcc->mPoly[k]);
         free(lhl->Pcc->mPoly);
         free(lhl->Pcc->mMatrix);                                                                                                                                                                                               
         free(lhl->Pcc);
         free(lhl->aKey);
         free(lhl->NGen->Bf);
         free(lhl->NGen);*/
		 
		 perseus_destroy(lhl);

         return -1;
      }

   return 0;
}

unsigned char *perseus_code(libperseus_hl_t *lhl, unsigned char *data, unsigned long int data_size, unsigned long int *encoded_data_size)
{
   /*unsigned int k;*/
   unsigned char *encoded_data;

   *encoded_data_size = 0L;

   if(!pcc_code(lhl->Pcc, data, data_size, &encoded_data, encoded_data_size, lhl->NGen, lhl->aKey))
      {
		perseus_destroy(lhl);
         /*for(k = 0;k < lhl->Pcc->mK;k++) free(lhl->Pcc->mPoly[k]);
         free(lhl->Pcc->mPoly);
         free(lhl->Pcc->mMatrix);                                                                                                                                                                                               
         free(lhl->Pcc);
         free(lhl->aKey);
         free(lhl->NGen->Bf);
         free(lhl->NGen);*/

         return NULL;
      }

   return encoded_data;
}

unsigned char *perseus_decode(libperseus_hl_t *lhl, unsigned char *encoded_data, unsigned long int encoded_data_size, unsigned long int *decoded_data_size)
{
   /*int k;*/
   unsigned char *decoded_data;

   *decoded_data_size = 0L;

   if(!pcc_decode(lhl->Pcc, lhl->NGen, lhl->aKey, encoded_data, encoded_data_size, &decoded_data, decoded_data_size))
     {
        perseus_destroy(lhl); 
         /*for(k = 0;k < lhl->Pcc->mK;k++) free(lhl->Pcc->mPoly[k]);
         free(lhl->Pcc->mPoly);
         free(lhl->Pcc->mMatrix);
         free(lhl->Pcc);
         free(lhl->aKey);
         free(lhl->NGen->Bf);
         free(lhl->NGen);*/
		 
         return NULL;
     }

   return decoded_data; 
}

void perseus_destroy(libperseus_hl_t *lhl)
{
   unsigned int k;

   if (lhl != NULL)
   {
       if (lhl->Pcc)
       {
           for(k = 0;k < lhl->Pcc->mK;k++) 
           {
               free(lhl->Pcc->mPoly[k]);
           }

           free(lhl->Pcc->mPoly);
           free(lhl->Pcc->mMatrix);     
           free(lhl->Pcc);
       }
         free(lhl->aKey->Bf);
         free(lhl->aKey);
         free(lhl->NGen);
      }
}
